/*****************************************************************************
* Keppe Messenger Bots (KMSB)
* Copyright (C) 2014 Keppe Project-Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/

#include "vBoxServerClient.h"
#include <QStringList>
#include <QEventLoop>
#include <QSettings>
#include <QProcess>
#include <QTimer>

// Keppe
#include <KMsgFw11Q>

// C Defines
#include <iostream>
using namespace std;

vBoxServerClient::vBoxServerClient()
{
}

void vBoxServerClient::run()
{
    QSettings *settings = new QSettings("VBoxServerClient.ini",QSettings::IniFormat);
    settings->beginGroup("Login");
    QString username = settings->value("Username","").toString();
    QString password = settings->value("Password","").toString();
    settings->endGroup();
    settings->beginGroup("VM");
    VBoxManage = settings->value("VBoxManage","VBoxManage").toString();
    settings->endGroup();
    settings->deleteLater();
    if (username == "" || password == "")
    {
        cout << "No Access Data for VBox Server Client!\n";
        return;
    }
    fw = new KMsgFw11Q();
    int ret = fw->loginUser(username,password);
    if (ret == 200)
    {
        int zt = 0;
        cout << "VBox Server Client started!\n";
        fw->setUserOnlineState(1);

whg:

        QEventLoop whl;
        QTimer::singleShot(50,&whl,SLOT(quit()));
        whl.exec();

        if (fw->isLoggedIn())

        {
            zt++;

            if (fw->isObjectIncoming())
            {
                objectIncomed(fw->readObject());
            }

            if (zt == 600)
            {
                zt = 0;
                fw->requestGetUserFriendRequests();
            }

            if (toSend.length() >= 1)
            {
                QStringList fromToSend = toSend;
                foreach(const QString& sendString, fromToSend)
                {
                    QString sendStr = sendString;
                    QStringList sendList = sendStr.split("&splt;");
                    if (sendList.length() >= 2)
                    {
                        fw->sendMessageToUser(sendList.at(0),sendList.at(1));
                    }
                    toSend.removeOne(sendStr);
                }
            }
        }
        else
        {
            fw->loginUser(username,password);
        }

        goto whg;
    }
    else
    {
        cout << "Access Data not correct for VBox!\n";
    }
}

void vBoxServerClient::objectIncomed(QString object)
{
    QString readstr = object.trimmed();
    QStringList readlist = readstr.split("<>");
    if (readlist.length() >= 2)
    {
        if (readlist.at(0) == "MessageFromUser")
        {
            QString message = readlist.at(1);
            QStringList msglist = message.split(": ");
            QString username = msglist.at(0);
            message = message.remove(username.length() + 2);

            cout << "VBox: " << message.toStdString().c_str() << "\n";

            if (message.toLower().contains("start") && !message.toLower().contains("stop") && !message.toLower().contains("freeze") && !message.toLower().contains("reset") && !message.toLower().contains("acpi"))
            {
                // Server starten
                QSettings auser(username + ".ini",QSettings::IniFormat);
                auser.beginGroup("VM");
                QString vboxvmname = auser.value("vboxvmname","").toString();
                auser.endGroup();
                if (vboxvmname != "")
                {
                    fw->sendMessageToUser(username,"Server start triggered!");
                    startvServer(username,vboxvmname);
                }
                else
                {
                    fw->sendMessageToUser(username,"You don't have a VirtualBox Server!");
                }
                auser.deleteLater();
            }
            else if (message.toLower().contains("stop") && !message.toLower().contains("start") && !message.toLower().contains("freeze") && !message.toLower().contains("reset") && !message.toLower().contains("acpi"))
            {
                // Server stoppen
                QSettings auser(username + ".ini",QSettings::IniFormat);
                auser.beginGroup("VM");
                QString vboxvmname = auser.value("vboxvmname","").toString();
                auser.endGroup();
                if (vboxvmname != "")
                {
                    fw->sendMessageToUser(username,"Server stop triggered!");
                    stopvServer(username,vboxvmname);
                }
                else
                {
                    fw->sendMessageToUser(username,"You don't have a VirtualBox Server!");
                }
                auser.deleteLater();
            }
            else if (message.toLower().contains("freeze") && !message.toLower().contains("start") && !message.toLower().contains("stop") && !message.toLower().contains("reset") && !message.toLower().contains("acpi"))
            {
                // Server einfrieren
                QSettings auser(username + ".ini",QSettings::IniFormat);
                auser.beginGroup("VM");
                QString vboxvmname = auser.value("vboxvmname","").toString();
                auser.endGroup();
                if (vboxvmname != "")
                {
                    fw->sendMessageToUser(username,"Server freeze triggered!");
                    freezevServer(username,vboxvmname);
                }
                else
                {
                    fw->sendMessageToUser(username,"You don't have a VirtualBox Server!");
                }
                auser.deleteLater();
            }
            else if (message.toLower().contains("reset") && !message.toLower().contains("start") && !message.toLower().contains("stop") && !message.toLower().contains("freeze") && !message.toLower().contains("acpi"))
            {
                // Server reset
                QSettings auser(username + ".ini",QSettings::IniFormat);
                auser.beginGroup("VM");
                QString vboxvmname = auser.value("vboxvmname","").toString();
                auser.endGroup();
                if (vboxvmname != "")
                {
                    fw->sendMessageToUser(username,"Server reset triggered!");
                    resetvServer(username,vboxvmname);
                }
                else
                {
                    fw->sendMessageToUser(username,"You don't have a VirtualBox Server!");
                }
                auser.deleteLater();
            }
            else if (message.toLower().contains("acpi") && !message.toLower().contains("start") && !message.toLower().contains("stop") && !message.toLower().contains("freeze") && !message.toLower().contains("reset"))
            {
                // Server Ausschaltknopf Druck simulieren
                QSettings auser(username + ".ini",QSettings::IniFormat);
                auser.beginGroup("VM");
                QString vboxvmname = auser.value("vboxvmname","").toString();
                auser.endGroup();
                if (vboxvmname != "")
                {
                    fw->sendMessageToUser(username,"Server acpi triggered!");
                    acpivServer(username,vboxvmname);
                }
                else
                {
                    fw->sendMessageToUser(username,"You don't have a VirtualBox Server!");
                }
                auser.deleteLater();
            }
            else if (message.toLower().contains("hi") || message.toLower().contains("hey") || message.toLower().contains("hay") || message.toLower().contains("hello") || message.toLower().contains("hallo") || message.toLower().contains("moin"))
            {
                fw->sendMessageToUser(username,"Hi " + username + "!");
            }
            else
            {
                fw->sendMessageToUser(username,"Sorry, i didn't understand!");
            }
        }
        else if (readlist.at(0) == "ReturnIntialize")
        {
            int id = 0;
            QString users;
            QString action;
            QString request;
            foreach(QString argstr,readlist)
            {
                if (argstr.left(5) == "--at=")
                {
                    action = argstr.remove(0,5).replace("&nbsp;"," ").replace("&amp;","&");
                }
                if (argstr.left(5) == "--rq=")
                {
                    request = argstr.remove(0,5).replace("&nbsp;"," ").replace("&amp;","&");
                }
                if (argstr.left(5) == "--id=")
                {
                    id = QVariant(argstr.remove(0,5)).toInt();
                }
                if (argstr.left(8) == "--users=")
                {
                    users = argstr.remove(0,8).replace("&nbsp;"," ").replace("&amp;","&").replace("&lt;&gt;","\n");
                }
            }
            if (request == "contactsrequests" && id == 200)
            {
                QStringList friendList = users.split("\n");
                friendList.removeAll("");
                friendList.removeAll("\r");
                friendList.removeAll("\n");
                friendList.removeAll("\r\n");
                foreach(const QString& newFriend,friendList)
                {
                    fw->addUserContact(newFriend);
                    cout << "VBox: " << newFriend.toStdString().c_str() << " contact added!\n";
                }
            }
        }
        else
        {
            cout << "VBox Special: " << readstr.toStdString().c_str() << "\n";
        }
    }
}

void vBoxServerClient::startvServer(QString username, QString vboxvmname)
{
    cout << "VBox Start triggered " << vboxvmname.toStdString().c_str() << "\n";
    QProcess *process = new QProcess();
    processLinkName[process] = username;
    connect(process,SIGNAL(readyRead()),this,SLOT(readed()));
    connect(process,SIGNAL(finished(int)),this,SLOT(stopped(int)));
    process->setReadChannelMode(QProcess::MergedChannels);
    process->setReadChannel(QProcess::StandardOutput);
    process->start("\"" + VBoxManage + "\" \"startvm\" \"" + vboxvmname + "\" \"--type\" \"headless\"");
}

void vBoxServerClient::stopvServer(QString username, QString vboxvmname)
{
    cout << "VBox Stop triggered " << vboxvmname.toStdString().c_str() << "\n";
    QProcess *process = new QProcess();
    processLinkName[process] = username;
    connect(process,SIGNAL(readyRead()),this,SLOT(readed()));
    connect(process,SIGNAL(finished(int)),this,SLOT(stopped(int)));
    process->setReadChannelMode(QProcess::MergedChannels);
    process->setReadChannel(QProcess::StandardOutput);
    process->start("\"" + VBoxManage + "\" \"controlvm\" \"" + vboxvmname + "\" \"poweroff\"");
}

void vBoxServerClient::freezevServer(QString username, QString vboxvmname)
{
    cout << "VBox Freeze triggered " << vboxvmname.toStdString().c_str() << "\n";
    QProcess *process = new QProcess();
    processLinkName[process] = username;
    connect(process,SIGNAL(readyRead()),this,SLOT(readed()));
    connect(process,SIGNAL(finished(int)),this,SLOT(stopped(int)));
    process->setReadChannelMode(QProcess::MergedChannels);
    process->setReadChannel(QProcess::StandardOutput);
    process->start("\"" + VBoxManage + "\" \"controlvm\" \"" + vboxvmname + "\" \"savestate\"");
}

void vBoxServerClient::acpivServer(QString username, QString vboxvmname)
{
    cout << "VBox Freeze triggered " << vboxvmname.toStdString().c_str() << "\n";
    QProcess *process = new QProcess();
    processLinkName[process] = username;
    connect(process,SIGNAL(readyRead()),this,SLOT(readed()));
    connect(process,SIGNAL(finished(int)),this,SLOT(stopped(int)));
    process->setReadChannelMode(QProcess::MergedChannels);
    process->setReadChannel(QProcess::StandardOutput);
    process->start("\"" + VBoxManage + "\" \"controlvm\" \"" + vboxvmname + "\" \"acpipowerbutton\"");
}

void vBoxServerClient::resetvServer(QString username, QString vboxvmname)
{
    cout << "VBox Freeze triggered " << vboxvmname.toStdString().c_str() << "\n";
    QProcess *process = new QProcess();
    processLinkName[process] = username;
    connect(process,SIGNAL(readyRead()),this,SLOT(readed()));
    connect(process,SIGNAL(finished(int)),this,SLOT(stopped(int)));
    process->setReadChannelMode(QProcess::MergedChannels);
    process->setReadChannel(QProcess::StandardOutput);
    process->start("\"" + VBoxManage + "\" \"controlvm\" \"" + vboxvmname + "\" \"reset\"");
}

void vBoxServerClient::readed()
{
    QProcess *process = (QProcess*)sender();
    QString username = processLinkName[process];
    QString readed = QString::fromUtf8(process->readAll());
    readed = readed.trimmed();
    toSend.append(username + "&splt;" + readed);
}

void vBoxServerClient::stopped(int ret)
{
    QProcess *process = (QProcess*)sender();
    QString username = processLinkName[process];
    if (ret == 0)
    {
        toSend.append(username + "&splt;" + ":D");
    }
    else if (ret == 1)
    {
        toSend.append(username + "&splt;" + ":(");
    }
    else
    {
        toSend.append(username + "&splt;" + "Return Code: " + QString::number(ret));
    }
    while (process->canReadLine())
    {
        QString readed = QString::fromUtf8(process->readAll());
        readed = readed.trimmed();
        toSend.append(username + "&splt;" + readed);
    }
    process->deleteLater();
}
